In order to win the prize for most cookies sold, my friend Alice and I are going to merge our Girl Scout Cookies orders and enter as one unit.
Each order is represented by an "order id" (an integer).
We have our lists of orders sorted numerically already, in lists. Write a function to merge our lists of orders into one sorted list.
For example:
my_list = [3, 4, 6, 10, 11, 15]
alices_list = [1, 5, 8, 12, 14, 19]
# Prints [1, 3, 4, 5, 6, 8, 10, 11, 12, 14, 15, 19]
print(merge_lists(my_list, alices_list))
First, we allocate our answer list, getting its size by adding the size of my_list and alices_list.
We keep track of a current index in my_list, a current index in alices_list, and a current index in merged_list. So at each step, there's a "current item" in alices_list and in my_list. The smaller of those is the next one we add to the merged_list!
But careful: we also need to account for the case where we exhaust one of our lists and there are still elements in the other. To handle this, we say that the current item in my_list is the next item to add to merged_list only if my_list is not exhausted AND, either:
def merge_lists(my_list, alices_list):
# Set up our merged_list
merged_list_size = len(my_list) + len(alices_list)
merged_list = [None] * merged_list_size
current_index_alices = 0
current_index_mine = 0
current_index_merged = 0
while current_index_merged < merged_list_size:
is_my_list_exhausted = current_index_mine >= len(my_list)
is_alices_list_exhausted = current_index_alices >= len(alices_list)
if (not is_my_list_exhausted and
(is_alices_list_exhausted or
my_list[current_index_mine] < alices_list[current_index_alices])):
# Case: next comes from my list
# My list must not be exhausted, and EITHER:
# 1) Alice's list IS exhausted, or
# 2) the current element in my list is less
# than the current element in Alice's list
merged_list[current_index_merged] = my_list[current_index_mine]
current_index_mine += 1
else:
# Case: next comes from Alice's list
merged_list[current_index_merged] = alices_list[current_index_alices]
current_index_alices += 1
current_index_merged += 1
return merged_list
The if statement is carefully constructed to avoid an IndexError from indexing past the end of a list. We take advantage of Python 3.6's short circuit evaluation and check first if the lists are exhausted.
time and additional space, where is the number of items in the merged list.
The added space comes from allocating the merged_list. There's no way to do this " in place" because neither of our input lists are necessarily big enough to hold the merged list.
But if our inputs were linked lists, we could avoid allocating a new structure and do the merge by simply adjusting the next pointers in the list nodes!
In our implementation above, we could avoid tracking current_index_merged and just compute it on the fly by adding current_index_mine and current_index_alices. This would only save us one integer of space though, which is hardly anything. It's probably not worth the added code complexity.
Trivia! Python's native sorting algorithm is called Timsort. It's actually optimized for sorting lists where subsections of the lists are already sorted. For this reason, a more naive algorithm:
def merge_sorted_lists(arr1, arr2):
return sorted(arr1 + arr2)
is actually faster until gets pretty big. Like 1,000,000.
Also, in Python 2.6+, there's a built-in function for merging sorted lists into one sorted list: heapq.merge().
What if we wanted to merge several sorted lists? Write a function that takes as an input a list of sorted lists and outputs a single sorted list with all the items from each list.
Do we absolutely have to allocate a new list to use for the merged output? Where else could we store our merged list? How would our function need to change?
We spent a lot of time figuring out how to cleanly handle edge cases.
Sometimes it's easy to lose steam at the end of a coding interview when you're debugging. But keep sprinting through to the finish! Think about edge cases. Look for off-by-one errors.
Do you have an answer?
Wanna review this one again later? Or do you feel like you got it all?
Mark as done Pin for review laterReset editor
Powered by qualified.io